import axios from 'axios'
import { Guid } from 'guid-typescript'

import CryptoJS from 'crypto-js'

import { randomString } from '@/util'
import store from '@/store'
import router from '@/router'

import { AllStateTypes } from '@/store/interface'

const state = store.state as AllStateTypes

const { $loading: loading, $dialog: dialog } = window

interface CommParam {
    token: string
    time: string
    nonce: string
    version: string
    reqid: string
    sign?: string
}

// 获取通用参数
const getCommParam = (): CommParam => {
    let token = state.user.token || 'Guest'
    let time = (new Date().getTime() / 1000).toFixed(0)
    let nonce = randomString()
    let version = '10000'
    let reqid = Guid.create().toString()
    return {
        token: token,
        time: time,
        nonce: nonce,
        version: version,
        reqid: reqid,
    }
}

// 计算请求签名
const calcReqSign = (body: string, param: CommParam): string => {
    // console.log(param.nonce)
    // console.log(param.reqid)
    // console.log(body)
    // console.log(param.nonce + body + param.reqid)
    // console.log(CryptoJS.MD5(param.nonce + body + param.reqid).toString())

    return CryptoJS.MD5(param.nonce + body + param.reqid).toString()
}

// 当前请求集合
const reqs = new Set<string>()

// 显示Loading
const showLoading = (reqId: string, full: boolean) => {
    reqs.add(reqId)
    setTimeout(() => {
        if (reqs.size > 0) {
            store.commit('loading/setLoading', {
                flag: true,
                full: full,
            })
            loading.start()
        }
    }, 300)
}

// 隐藏Loading
const hideLoading = (reqId: string) => {
    if (reqId == 'All') {
        reqs.clear()
    } else {
        reqs.delete(reqId)
    }
    if (reqs.size > 0) {
        return
    }
    store.commit('loading/setLoading', {
        flag: false,
        full: true,
    })
    loading.finish()
}

// 显示提示框
const showMessage = (msg: string) => {
    dialog.destroyAll()
    dialog.error({
        title: '请求错误',
        content: msg,
        bordered: true,
        closable: false,
        maskClosable: false,
        positiveText: '知道了',
    })
}

const Http = axios.create()

Http.defaults.baseURL = import.meta.env.VITE_APIX_ROOT
Http.defaults.timeout = 5 * 60 * 1000

Http.interceptors.request.use(
    config => {
        let param = getCommParam()
        let body = config.data ? JSON.stringify(config.data) : ''
        if (!config.url?.endsWith('upload')) {
            if (import.meta.env.VITE_MODE_TYPE == 'prod') {
                let key = CryptoJS.MD5(param.nonce + param.time).toString()
                let iv = CryptoJS.MD5(key).toString().substring(8, 24)
                let enx = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(body), CryptoJS.enc.Utf8.parse(key), {
                    iv: CryptoJS.enc.Utf8.parse(iv),
                    mode: CryptoJS.mode.CBC,
                    padding: CryptoJS.pad.Pkcs7,
                })
                config.data = CryptoJS.enc.Base64.stringify(enx.ciphertext)
            } else {
                config.data = body
            }
        } else {
            if (config.headers) {
                config.headers['Content-Type'] = 'multipart/form-data;charset=UTF-8'
            }
            param.sign = calcReqSign('{}', param)
        }

        param.sign = calcReqSign(config.data, param)

        showLoading(param.reqid, false)

        config.params = param
        if (config.headers) {
            config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
        }
        return config
    },
    error => {
        
        hideLoading('all')
        showMessage('请求未能成功发送，请检查网络连接')
        return Promise.reject(error)
    }
)

Http.interceptors.response.use(
    response => {
        if (typeof response.data == 'string') {
            let key = CryptoJS.MD5(response.config.params.time + response.config.params.reqid).toString()
            let iv = CryptoJS.MD5(key).toString().substring(8, 24)

            let decrypt = CryptoJS.AES.decrypt(CryptoJS.enc.Base64.stringify(CryptoJS.enc.Base64.parse(response.data)), CryptoJS.enc.Utf8.parse(key), {
                iv: CryptoJS.enc.Utf8.parse(iv),
                mode: CryptoJS.mode.CBC,
                padding: CryptoJS.pad.Pkcs7,
            })
            response.data = JSON.parse(decrypt.toString(CryptoJS.enc.Utf8))
        }

        let data = response.data

        if (import.meta.env.VITE_MODE_TYPE == 'dev' && !response.config.url?.endsWith('upload')) {
            console.log('API >> ' + response.config.url, JSON.parse(response.config.data || '{}'), data)
        }
        if (data.stat.err == 15) {
            store.commit('user/signout')
            showMessage(data.stat.msg)
            router.replace('/login')
        } else if (data.stat.err > 0) {
            showMessage(`「${data.stat.err}」${data.stat.msg}`)
        }
        hideLoading(response.config.params.reqid)
        return data
    },
    error => {
        console.log(error)
        hideLoading(error.config.params.reqid)
        showMessage('请求未能成功发送，请检查网络连接')
        return Promise.reject(error)
    }
)

export { Http }
